function AppAssistant() {
	Mojo.Log.info('--- BEGIN AppAssistant()');
	
	this.closePreferences = false;
	this.fromLauncher = false;
	this.calendarEvents = new Array();

	this.refreshTimer = null;
	
	this.nowUTC = null;
	this.thenUTC = null;
	this.todayStartUTC = null;
}

AppAssistant.prototype.setup = function(){
	Mojo.Log.info('--- BEGIN setup()');
	
	try {
	    // create db
    	var dboptions = {name: "dbupdates", replace: false};
   		this.depot = new Mojo.Depot(dboptions, this.dbConnectionSuccess, this.dbConnectionFailure);
/*		
		// read preferences
    	this.depot.simpleGet("preferences",
				this.gotPreferences.bind(this),
				function() {Mojo.Log.error("Error reading preferences");this.getCalendars();}
			);
*/
	} catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.setup()', e);
	}
}

AppAssistant.prototype.gotPreferences = function(result) {
	Mojo.Log.info('--- BEGIN gotPreferences(), result: ' + result);
	
	try {
		if (result != null) {
			Preferences = result;
			
			this.getCalendars();
		}
	} catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.gotPreferences()', e);
	}
}

AppAssistant.prototype.dbConnectionSuccess = function(){  
    Mojo.Log.info('--- BEGIN dbConnectionSuccess()');
}

AppAssistant.prototype.dbConnectionFailure = function(transaction, result){  
    Mojo.Log.error('--- BEGIN dbConnectionFailure(): ' + result.message); 
}

//handleLaunch - called by the framework when the application is asked to launch
AppAssistant.prototype.handleLaunch = function(launchParams) {
	Mojo.Log.info("--- BEGIN AppAssistant.handleLaunch()");
	try {
		var appController = Mojo.Controller.getAppController();
		
		if (!launchParams) {
			// app was launched directly from the launcher
			Mojo.Log.info('--- AppAssistant.handleLaunch: Launched from App Launcher');
			this.fromLauncher = true;

			//this.openPreferences();
			//this.getCalendars();
			
					// read preferences
    	this.depot.simpleGet("preferences",
				this.gotPreferences.bind(this),
				function() {Mojo.Log.error("Error reading preferences");this.getCalendars();}
			);
		}		
	} catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.prototype.handleLaunch()', e);
	}
}


AppAssistant.prototype.cleanup = function() {
	try {
		Mojo.Log.info('--- BEGIN AppAssistant.cleanup()');
		
		// Close all stages
		Mojo.Controller.getAppController().closeAllStages();
	} catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.cleanup()', e);
	}
}


AppAssistant.prototype.createPreferencesDashboard = function(icon, title, message){
	try {
		Mojo.Log.info('--- BEGIN AppAssistant.createPreferencesDashboard(', icon, title, message, ')');
		
		var appController = Mojo.Controller.getAppController();

		var dashboardStage = appController.getStageController('preferencesDashboardStage');
		if (dashboardStage) {
			Mojo.Log.info('--- AppAssistant.createPreferencesDashboard: Dashboard already existis, nothing to do');
		}
		else {
			Mojo.Log.info('--- AppAssistant.createPreferencesDashboard: createStageWithCallback: title: ' + title + ', message: ' + message);
			var pushDashboard = function(stageController) {
				Mojo.Log.info('--- AppAssistant.createPreferencesDashboard: stageController.pushScene: title: ' + title + ', message: ' + message);
				stageController.pushScene('dashboard', 'preferences', icon, title, message);
			};
			Mojo.Log.info('--- AppAssistant.createPreferencesDashboard: createStageWithCallback');
			this.controller.createStageWithCallback(
				{
					name: 'preferencesDashboardStage',
					lightweight: true,
					icon: icon
				}, 
				pushDashboard.bind(this),
				'dashboard'
			);
		}
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.createPreferencesDashboard()', e);
	}
}

AppAssistant.prototype.openPreferences = function() {
	Mojo.Log.info("--- BEGIN AppAssistant.openPreferences()");
	try {
		var appController = Mojo.Controller.getAppController();
		
		var preferencesCardStageController = appController.getStageController("preferencesCardStage");
		if (preferencesCardStageController) {
			preferencesCardStageController.swapScene('preferences', this);
			preferencesCardStageController.activate();
		}
		else {
			var pushCardScene = function(stageController){
				Mojo.Log.info('--- AppAssistant.openPreferences.pushCardScene: stageController: ' + stageController);
				stageController.swapScene('preferences', this);
			}
			var stageArguments = {
				name: "preferencesCardStage",
				lightweight: true
			};
			appController.createStageWithCallback(stageArguments, pushCardScene.bind(this), 'card');
		}
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.openPreferences", e);
	}	
}

AppAssistant.prototype.refreshCalendarEvents = function() {
	Mojo.Log.error("--- BEGIN AppAssistant.refreshCalendarEvents()");
	try {
		this.calcNowThenUTC();
		
		this.closeAllCalendarEvents();
		
		window.setTimeout(this.getCalendars.bind(this), 100);
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.refreshCalendarEvents", e);
	}
}

AppAssistant.prototype.closeAllCalendarEvents = function() {
	Mojo.Log.info("--- BEGIN AppAssistant.closeAllCalendarEvents()");
	try {
		var appController = Mojo.Controller.getAppController();
		this.calendarEventsToClose = new Array();
		
		for (var i = 0; i < this.calendarEvents.length; i++) {
			var thisEvent = this.calendarEvents[i];
			appController.closeStage(thisEvent.getShortId());
		}
		this.calendarEvents = new Array();
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.closeAllCalendarEvents", e);
	}
}

AppAssistant.prototype.getCalendars = function () {
	Mojo.Log.info("--- BEGIN AppAssistant.getCalendars()");

	try {
		new Mojo.Service.Request('palm://com.palm.calendar', {
			method: 'getCalendarsByAccount',
			parameters: {
				"subscribe": false
			},
			onSuccess: this.gotCalendars.bind(this),
			onFailure: function(events){
				Mojo.Log.error("--- ERROR: AppAssistant.closeAllCalendarEvents: " + events.errorCode + " " + events.errorText);
				Mojo.Controller.errorDialog($L("Error! Cannot read calendars."));
			}
		});
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.getCalendars", e);
	}
}


AppAssistant.prototype.gotCalendars = function(response){
	Mojo.Log.info("--- BEGIN AppAssistant.gotCalendars()");
	
	try {
	
		Preferences.calendars = [];
		// loop through accounts
		for (var i = 0; i < response.accounts.length; i++) {
			// loop through calendars
			for (var j = 0; j < response.accounts[i].calendars.length; j++) {
				var thisCal = response.accounts[i].calendars[j];
				thisCal.display = true;
				thisCal.id = 'id' + thisCal.id;
				for (var k = 0, len = Preferences.calendarsToHide.length; k < len; k++) {
					if (thisCal.id == Preferences.calendarsToHide[k].id) {
						thisCal.display = false;
						break;
					}
				}
				Preferences.calendars.push(thisCal);
			}
		}
		
		if (this.fromLauncher) {
			this.fromLauncher = false;
			this.openPreferences();
			
			// create preferences dashboard entry
			this.createPreferencesDashboard("icon.png", "UpDates", "Preferences");
		}
		else {
			this.getEvents();
		}
		
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.gotCalendars", e);
	}	
}

AppAssistant.prototype.getEvents = function() {
	Mojo.Log.info("--- BEGIN AppAssistant.getEvents(): Get Events from",new Date(this.nowUTC).toUTCString(),":",new Date(this.thenUTC).toUTCString());
	
	try {
		// get calendar events
		new Mojo.Service.Request('palm://com.palm.calendar', {
			method: 'getEvents',
			parameters: {
				"calendarId": "all",
				"startDate": this.nowUTC,
				"endDate": this.thenUTC,
				"subscribe": false,
				"freeTimes": true
			},
			onSuccess: this.gotEvents.bind(this),
			onFailure: function(resp){
				Mojo.Log.info("--- ERROR: AppAssistant.getEvents: " + resp.errorCode + " " + resp.errorText);
				Mojo.Controller.errorDialog("Error! Cannot read calendar events.");
			}
		});
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.getEvents", e);
	}
}

AppAssistant.prototype.gotEvents = function(resp) {
	Mojo.Log.info("--- BEGIN AppAssistant.gotEvents");

	try {
		var appController = Mojo.Controller.getAppController();
	
		var days = resp.days.length;
		Mojo.Log.info("--- AppAssistant.gotEvents: Found events for " + days + " days.");
		
		// loop through days
		for (var day = 0; day < days; day++) {
			
			// all day events
			for (var event = 0; event < resp.days[day].allDayEvents.length; event++) {
			
				var thisEvent = resp.days[day].allDayEvents[event];
				
				Mojo.Log.info("--- AppAssistant.gotEvents: found allDay event: id: " + thisEvent.id +
					", subject: " + thisEvent.subject +	", start: " + thisEvent.start + ", end: " +	thisEvent.end);
				
				// check if event is to hide
				if (this.isEventToHide(thisEvent)) {
					continue;
				}
				
				// if thisEvent already in calendarEvents, only update start/end
				this.createCalendarEvent(thisEvent);
			}

			// timed events
			for (var event = 0; event < resp.days[day].events.length; event++) {
								
				var thisEvent = resp.days[day].events[event];
	
				Mojo.Log.info("--- AppAssistant.gotEvents: found timed event: id: " + thisEvent.id + 
					", subject: " + thisEvent.subject +	", start: " + thisEvent.start +	", end: " + thisEvent.end);
				
				// check if event is to hide
				if (this.isEventToHide(thisEvent)) {
					continue;
				}
				
				// if thisEvent already in calendarEvents, only update start/end
				this.createCalendarEvent(thisEvent);
			}
		}
		
		if (this.closePreferences) {
			appController.closeStage('preferencesCardStage');
			this.closePreferences = false;	
		}
	
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.gotMyEvents", e);
	}
}

AppAssistant.prototype.createCalendarEvent = function(thisEvent) {
	Mojo.Log.info('--- BEGIN AppAssistant.createCalendarEvent()');
	try {
		var thisCalendarEvent = new CalendarEvent(thisEvent.id, thisEvent.start, thisEvent.end,
				thisEvent.location,	thisEvent.calendarId, thisEvent.subject, thisEvent.note, thisEvent.allDay);
		this.createCalendarEventDashboard(this.getIcon(thisCalendarEvent), thisCalendarEvent);
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.createCalendarEvent()', e);
	}
}

AppAssistant.prototype.createCalendarEventDashboard = function(icon, calendarEvent) {
	Mojo.Log.info('--- BEGIN AppAssistant.createCalendarEventDashboard(', icon, title, message, ')');
	try {
		
		var appController = Mojo.Controller.getAppController();
		var calendarEventDashboardStage = calendarEvent.getShortId();
		
		var title = calendarEvent.getDashboardTitle();
		var message = calendarEvent.getDashboardMessage();
		
		var dashboardStage = appController.getStageController(calendarEventDashboardStage);
		if (dashboardStage) {
			Mojo.Log.info('--- AppAssistant.createCalendarEventDashboard: Dashboard already existis, nothing to do');
		}
		else {
			Mojo.Log.info('--- AppAssistant.createCalendarEventDashboard: createStageWithCallback: title: ' + title + ', message: ' + message);
			var pushDashboard = function(stageController) {
				Mojo.Log.info('--- AppAssistant.createCalendarEventDashboard: stageController.pushScene: title: ' + title + ', message: ' + message);
				stageController.pushScene('dashboard', 'calendarEvent', icon, title, message, calendarEvent);
			};
			try {
				this.controller.createStageWithCallback({
					name: calendarEventDashboardStage,
					lightweight: true,
					icon: icon
				}, pushDashboard, 'dashboard');
			}
			catch (error) {
				if (error.message.indexOf("cannot create two stages with the same name") != -1) {
					// dates over several days create several events with same id
					Mojo.Log.warning('--- AppAssistant.createCalendarEventDashboard: found multiple events with same id: ' + calendarEvent.id);
					return;
				}
				else {
					throw error;
				}
			}
			this.calendarEvents.push(calendarEvent);
			this.setRefreshTimerInterval();
		}
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.createCalendarEventDashboard()', e);
	}
}

AppAssistant.prototype.setRefreshTimerInterval = function() {
	Mojo.Log.info("--- BEGIN AppAssistant.setRefreshTimerInterval()");
	try {
		// cancel refresh timer
		var appController = Mojo.Controller.getAppController();
		var preferencesDashboardStageController = appController.getStageController("preferencesDashboardStage");
		Mojo.Log.info("--- AppAssistant.setRefreshTimerInterval: preferencesDashboardStageController: " + preferencesDashboardStageController + ", this.refreshTimer: " + this.refreshTimer);
		if (this.refreshTimer != null) {
			Mojo.Log.info("--- AppAssistant.setRefreshTimerInterval: clearTimeout");
			preferencesDashboardStageController.window.clearInterval(this.refreshTimer);
		}
		
		// set new refresh timer
		var timeToRefresh = (Preferences.refreshHours * 60 + Preferences.refreshMinutes) * 60 * 1000;
		this.refreshTimer = preferencesDashboardStageController.window.setInterval(this.refreshCalendarEvents.bind(this), timeToRefresh);
		Mojo.Log.info("--- AppAssistant.setRefreshTimerInterval: timeToRefresh: " + timeToRefresh);
				
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.setRefreshTimerInterval", e);
	}
}

/***************************/
/* --- HELPER-METHODEN --- */
/***************************/

AppAssistant.prototype.isEventToHide = function(thisEvent) {
	Mojo.Log.info('--- BEGIN AppAssistant.isEventToHide()');
	try {
	
		// check event limit	
		if (this.eventLimitReached()) {
			return true;
		}
		// check for time stamps
		if ((thisEvent.endTimestamp < (Preferences.showPassedEvents ? this.todayStartUTC : this.nowUTC)) ||
				(thisEvent.startTimestamp > this.thenUTC)) {
			return true;
		}
		
		// check preferences
		if ((thisEvent.allDay == true && Preferences.showAllDayEvents == false) ||
				(thisEvent.allDay == false && Preferences.showTimedEvents == false)) {
			return true;
		}
		
		// check if event.calendar is on calendars to hide list
		for (var i = 0; i < Preferences.calendarsToHide.length; i++) {
			var hideCalendar = Preferences.calendarsToHide[i];
			if (thisEvent.calendarId == hideCalendar.id) {
				return true;
			}
		}		
		
		return false;
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.isEventToHide()', e);
	}
}

AppAssistant.prototype.calcNowThenUTC = function(){
	Mojo.Log.info('--- BEGIN AppAssistant.calcNowThenUTC()');
	try {
		this.calcTodayStartUTC();
		this.calcNowUTC();
		this.calcThenUTC();
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.calcNowThenUTC()', e);
	}
}

AppAssistant.prototype.calcNowUTC = function(){
	Mojo.Log.info('--- BEGIN AppAssistant.calcNowUTC()');
	try {
		var nowDate = new Date();
		this.nowUTC = Date.UTC(nowDate.getUTCFullYear(), nowDate.getUTCMonth(), nowDate.getUTCDate(),
				nowDate.getUTCHours(), nowDate.getUTCMinutes());
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.calcNowUTC()', e);
	}
}

AppAssistant.prototype.calcThenUTC = function(){
	Mojo.Log.info('--- BEGIN AppAssistant.calcThenUTC()');
	try {
		var thenDate = new Date();
		this.thenUTC = this.calcDate(thenDate, Preferences.upcomingDays, false);
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.calcThenUTC()', e);
	}
}

AppAssistant.prototype.calcTodayStartUTC = function(){
	Mojo.Log.info('--- BEGIN AppAssistant.calcTodayStartUTC()');
	try {
		var todayStartDate = new Date();
		this.todayStartUTC = this.calcDate(todayStartDate, 0, true);
	}
	catch (e) {
		Mojo.Log.error('--- ERROR: AppAssistant.calcTodayStartUTC()', e);
	}
}

AppAssistant.prototype.calcDate = function (date, days, startOfDay) {
	Mojo.Log.info("--- BEGIN AppAssistant.calcDate()");
	
	try {
		newDate = new Date(date);
		// to show events of whole day
		if (startOfDay) {
			newDate.setHours(0, 0, 0, 0);
		}
		else {
			newDate.setHours(23, 59, 59, 999);
		}
		
		dateUTC = Date.UTC(newDate.getUTCFullYear(), newDate.getUTCMonth(), newDate.getUTCDate(),
					newDate.getUTCHours(), newDate.getUTCMinutes());
		
		dateUTC += days * 24 * 60 * 60 * 1000;
		
		return dateUTC;
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.calcDate", e);
	}
}

AppAssistant.prototype.eventLimitReached = function () {
	Mojo.Log.info("--- BEGIN AppAssistant.eventLimitReached()");
	
	try {
		if (Preferences.maximumEvents == 0) {
			return false;
		}
		return (this.calendarEvents.length >= Preferences.maximumEvents);		
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.eventLimitReached", e);
	}
}

AppAssistant.prototype.getIcon = function(calendarEvent){
	Mojo.Log.info("--- BEGIN AppAssistant.getIcon()");
	try {
		var nowDate = new Date();
		var eventDate = new Date(calendarEvent.getEventStart());
		
		if (eventDate.getTime() <= nowDate.getTime() + 1 * 1000 * 60 * 60 * 24) {
			return "images/date_2.png"
		}
		else {
			return "images/date_1.png"
		}
		
	} catch (e) {
		Mojo.Log.error("--- ERROR: AppAssistant.getIcon", e);
	}	
}
